use anyhow::{Context, Result};
use axum::{
    body::Bytes,
    extract::{Multipart, Path, State},
    http::{HeaderMap, StatusCode},
    response::{IntoResponse, Response},
    routing::{get, post},
    Router,
};
use std::path::Path as StdPath;
use std::sync::Arc;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio_util::io::ReaderStream;
use crate::{config::Config, storage::Storage};

pub fn create_router(config: Config, storage: Arc<Storage>) -> Router {
    Router::new()
        .route("/upload", post(upload_package))
        .route("/dists/:distribution/:component/binary-:architecture/*path", get(serve_file))
        .route("/pool/main/:package_name/:file_name", get(serve_file))
        .route("/gpg-key", get(serve_gpg_key))
        .with_state((Arc::new(config), storage))
}

async fn serve_file(
    State((config, storage)): State<(Arc<Config>, Arc<Storage>)>,
    Path(path): Path<String>,
) -> Result<impl IntoResponse, AppError> {
    let file_path = storage.root_path().join(&path);
    
    if !file_path.exists() {
        return Err(AppError::NotFound);
    }
    
    let file = File::open(&file_path).await?;
    let stream = ReaderStream::new(file);
    
    let mut headers = HeaderMap::new();
    
    // 设置正确的 MIME 类型
    if path.ends_with(".deb") {
        headers.insert("Content-Type", "application/vnd.debian.binary-package".parse()?);
    } else if path.ends_with(".gz") {
        headers.insert("Content-Type", "application/gzip".parse()?);
    } else if path.ends_with(".gpg") {
        headers.insert("Content-Type", "application/pgp-signature".parse()?);
    } else {
        headers.insert("Content-Type", "text/plain".parse()?);
    }
    
    Ok((headers, stream.into_response()))
}

async fn serve_gpg_key(
    State((_, storage)): State<(Arc<Config>, Arc<Storage>)>,
) -> Result<impl IntoResponse, AppError> {
    let key_path = storage.gpg_key_path();
    
    if !key_path.exists() {
        return Err(AppError::NotFound);
    }
    
    let mut file = File::open(key_path).await?;
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).await?;
    
    let mut headers = HeaderMap::new();
    headers.insert("Content-Type", "application/pgp-keys".parse()?);
    
    Ok((headers, contents))
}

async fn upload_package(
    State((config, storage)): State<(Arc<Config>, Arc<Storage>)>,
    headers: HeaderMap,
    mut multipart: Multipart,
) -> Result<impl IntoResponse, AppError> {
    // 检查上传密钥
    if let Some(upload_secret) = &config.server.upload_secret {
        if let Some(auth_header) = headers.get("Authorization") {
            if auth_header != format!("Bearer {}", upload_secret) {
                return Err(AppError::Unauthorized);
            }
        } else {
            return Err(AppError::Unauthorized);
        }
    }
    
    while let Some(field) = multipart.next_field().await? {
        let file_name = field.file_name()
            .map(ToString::to_string)
            .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
        
        let data = field.bytes().await?;
        
        // 保存上传的文件到临时目录
        let temp_path = storage.save_incoming_file(&file_name, &data).await?;
        
        // 验证是否为有效的 .deb 文件
        if !is_valid_deb_package(&temp_path).await {
            fs::remove_file(&temp_path).await?;
            return Err(AppError::InvalidPackage);
        }
        
        // 移动到永久存储
        let dest_path = format!("pool/main/{}", file_name);
        storage.move_to_repository(&temp_path, &dest_path).await?;
        
        log::info!("上传软件包成功: {}", dest_path);
        
        return Ok((
            StatusCode::CREATED,
            format!("软件包上传成功: {}", dest_path),
        ));
    }
    
    Err(AppError::UploadError("没有上传文件".into()))
}

async fn is_valid_deb_package(path: &StdPath) -> bool {
    // 简化的验证：检查文件头部是否包含 "!<arch>" 魔术字节
    if let Ok(mut file) = File::open(path).await {
        let mut header = [0u8; 8];
        if file.read_exact(&mut header).await.is_ok() {
            return &header == b"!<arch>\n";
        }
    }
    false
}

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("未找到资源")]
    NotFound,
    #[error("未授权访问")]
    Unauthorized,
    #[error("无效的软件包格式")]
    InvalidPackage,
    #[error("上传错误: {0}")]
    UploadError(String),
    #[error("服务器内部错误")]
    Internal(#[from] anyhow::Error),
}

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let status = match self {
            AppError::NotFound => StatusCode::NOT_FOUND,
            AppError::Unauthorized => StatusCode::UNAUTHORIZED,
            AppError::InvalidPackage => StatusCode::BAD_REQUEST,
            AppError::UploadError(_) => StatusCode::BAD_REQUEST,
            AppError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
        };
        
        (status, self.to_string()).into_response()
    }
}